using Config;
using Koakuma.Game.Characters;
using Koakuma.Proto;
using System;
using System.Threading.Tasks;
using UnityEngine;

namespace Koakuma.Game.Scenes.Dungeons
{
    public class SpawnMonster : MonoBehaviour
    {
        public Spawner spawner;
        public int configID;
        public int? index;

        private Mesh[] meshes;
        private bool meshDirty;

        private void OnDrawGizmos()
        {
            if (spawner == null || spawner.spawnerSettings == null)
                return;

            if (index == null)
            {
                for (int i = 0; i < spawner.spawnerSettings.monsterReference.Count; i++)
                {
                    MonsterSpawnReference monsterReference = spawner.spawnerSettings.monsterReference[i];
                    if (monsterReference.id == configID)
                    {
                        index = i;
                        break;
                    }
                }
            }

            if (!index.HasValue || index < 0 || index >= spawner.spawnerSettings.monsterReference.Count)
                return;

            MonsterSpawnReference reference = spawner.spawnerSettings.monsterReference[index.Value];

            if (meshes == null || meshes.Length == 0 || meshDirty)
            {
                SkinnedMeshRenderer[] renderer = reference.obj.GetComponentsInChildren<SkinnedMeshRenderer>();
                meshes = new Mesh[renderer.Length];
                for (int i = 0; i < renderer.Length; i++)
                {
                    meshes[i] = renderer[i].sharedMesh;
                }
                meshDirty = false;
            }

            foreach (var mesh in meshes)
            {
                Gizmos.DrawMesh(mesh, 0, transform.position, transform.rotation * Quaternion.Euler(-90, 0, 0), transform.localScale);
            }
#if UNITY_EDITOR
            UnityEditor.Handles.Label(transform.position, reference.name);
#endif
        }

        private void Start()
        {
            GameManager.Message.Subscribe<MessageType.ActiveMonsterSpawner>(OnActiveMonsterSpawner);
            transform.localScale = Vector3.one * 5;
        }

        private void OnDestroy()
        {
            GameManager.Message.Unsubscribe<MessageType.ActiveMonsterSpawner>(OnActiveMonsterSpawner);
        }

        private void StartSpawn()
        {
            if (configID == 0)
                return;

            CharacterConfig characterConfig = CharacterConfig.ByID(configID);

            CharacterData characterData = new CharacterData()
            {
                characterInfo = new Proto.CharacterInfo()
                {
                    configID = configID,
                    team = CharacterTeam.Monster,
                    skills = ListPool<SkillInfo>.Obtain(),
                    characterAttributes = DictionaryPool<CharacterAttributeType, long>.Obtain(),
                },
                position = transform.position,
                rotation = transform.rotation,
                scene = GameManager.ECS.World.GameScene.InstanceID,
                useHQ = false,
            };

            foreach (var skill in characterConfig.Skills)
            {
                characterData.characterInfo.skills.Add(new SkillInfo()
                {
                    configID = skill,
                    level = 4,
                });
            }

            characterData.characterInfo.characterAttributes[CharacterAttributeType.Strength] = (long)(characterConfig.Strength * 1000);
            characterData.characterInfo.characterAttributes[CharacterAttributeType.Intelligence] = (long)(characterConfig.Intelligence * 1000);
            characterData.characterInfo.characterAttributes[CharacterAttributeType.Dexterity] = (long)(characterConfig.Dexterity * 1000);
            characterData.characterInfo.characterAttributes[CharacterAttributeType.Vitality] = (long)(characterConfig.Vitality * 1000);
            characterData.characterInfo.characterAttributes[CharacterAttributeType.BaseHP] = (long)(characterConfig.Life * 1000);
            characterData.characterInfo.characterAttributes[CharacterAttributeType.MaxFury] = (long)(characterConfig.Fury * 1000);
            characterData.characterInfo.characterAttributes[CharacterAttributeType.Damage] = (long)(characterConfig.Damage * 1000);
            characterData.characterInfo.characterAttributes[CharacterAttributeType.Critical] = (long)Math.Floor(characterConfig.CriticalHit * 1000);
            characterData.characterInfo.characterAttributes[CharacterAttributeType.CriticalDamage] = (long)Math.Floor(characterConfig.CriticalHitDamage * 1000);
            characterData.characterInfo.characterAttributes[CharacterAttributeType.Evasion] = (long)Math.Floor(characterConfig.Evasion * 1000);
            characterData.characterInfo.characterAttributes[CharacterAttributeType.Block] = (long)Math.Floor(characterConfig.Block * 1000);
            characterData.characterInfo.characterAttributes[CharacterAttributeType.MoveSpeed] = (long)Math.Floor(characterConfig.MS * 1000);
            characterData.characterInfo.characterAttributes[CharacterAttributeType.Level] = 1000;

            CharacterEntity monsterEntity = CharacterFactory.CreateMonster(characterData);
            if (monsterEntity != null)
            {
                GameManager.ECS.SendMessageToEntity(monsterEntity.InstanceID, new EntityMessageType.CharacterVitalize()).Coroutine();
            }

            ListPool<SkillInfo>.Release(characterData.characterInfo.skills);
            DictionaryPool<CharacterAttributeType, long>.Release(characterData.characterInfo.characterAttributes);
        }

        public void UpdateMesh()
        {
            meshDirty = true;
            transform.localScale = Vector3.one * 5;
        }

        private async Task OnActiveMonsterSpawner(MessageType.ActiveMonsterSpawner arg)
        {
            StartSpawn();
            transform.localScale = Vector3.one * 5;
            await Task.Yield();
        }
    }
}
